import { AssetManager, assetManager, Canvas, Component, director, game, Node, resources, Size, Sprite, UITransform, v2, v3, v4, Vec2, Vec3, Vec4, view, warn, Widget } from "cc";

const __Global__ = window ?? globalThis;
if(!Reflect.has(__Global__, 'abi')) Reflect.set(__Global__, 'abi', {__ability__: 'Ab_ability_bA'});

['Ab_sp_bA', 'Ab_size_bA', 'Ab_vector_bA', 'Ab_cc_bA']
.forEach(space_name=>{
	if(!Reflect.has(abi, space_name)) Reflect.set(abi, space_name, {[`${space_name}_space`]: space_name});
});

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_initTime_bA', {
	get() {
		return Reflect.get(game, '_initTime');
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_totalTime_bA', {
	get() {
		return game.totalTime;
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_frameStartTime_bA', {
	get() {
		return game.frameStartTime - abi.Ab_cc_bA.Ab_initTime_bA;
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_residueTime_bA', {
	get() {
		return abi.Ab_cc_bA.Ab_frameStartTime_bA+abi.Ab_cc_bA.Ab_frameTime_bA-abi.Ab_cc_bA.Ab_totalTime_bA;
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_frameTime_bA', {
	get() {
		return game.frameTime;
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_is_long_screen_bA', {
	get(){
		let [R, r] = [abi.Ab_size_bA.Ab_canvasSize_bA, abi.Ab_size_bA.Ab_designSize_bA].map(s=>s.width/s.height);
		return r > R;
	},
	enumerable: true,
	configurable: false,
});

if(typeof requestIdleCallback !== 'undefined'){
	abi.Ab_cc_bA.Ab_IdleCallback_bA = function(call, args, complete, options){
		if(options){
			if(!Reflect.has(options, 'start_stamp')) options.start_stamp = performance.now();
			if(!Reflect.has(options, 'timeout')) options.timeout = 100;
		}else options = {start_stamp: performance.now(), timeout: 100};

		requestIdleCallback(()=>{
			if(abi.Ab_cc_bA.Ab_residueTime_bA>0 || performance.now()-options.start_stamp >= options.timeout){
				Promise.resolve(call(...args)).then(r=> typeof complete == 'function' ? complete(r, args) : void 0);
			}else abi.Ab_cc_bA.Ab_IdleCallback_bA(call, args, complete, options);
		});
	}
}else if(typeof requestAnimationFrame !== 'undefined'){
	abi.Ab_cc_bA.Ab_IdleCallback_bA = function(call, args, complete, options){
		if(options){
			if(!Reflect.has(options, 'start_stamp')) options.start_stamp = performance.now();
			if(!Reflect.has(options, 'timeout')) options.timeout = 100;
		}else options = {start_stamp: performance.now(), timeout: 100};
		requestAnimationFrame(()=>{
			if(abi.Ab_cc_bA.Ab_residueTime_bA>0 || performance.now()-options.start_stamp >= options.timeout){
				Promise.resolve(call(...args)).then(r=> typeof complete == 'function' ? complete(r, args) : void 0);
			}else abi.Ab_cc_bA.Ab_IdleCallback_bA(call, args, complete, options);
		});
	}
}else{
	abi.Ab_cc_bA.Ab_IdleCallback_bA = function(call, args, complete, options){
		if(options){
			if(!Reflect.has(options, 'start_stamp')) options.start_stamp = performance.now();
			if(!Reflect.has(options, 'timeout')) options.timeout = 100;
		}else options = {start_stamp: performance.now(), timeout: 100};
		setTimeout(()=>{
			if(abi.Ab_cc_bA.Ab_residueTime_bA>0 || performance.now()-options.start_stamp >= options.timeout){
				Promise.resolve(call(...args)).then(r=> typeof complete == 'function' ? complete(r, args) : void 0);
			}else abi.Ab_cc_bA.Ab_IdleCallback_bA(call, args, complete, options);
		}, 0);
	}
}

abi.Ab_cc_bA.Ab_frameWhile_bA = function(list, call){
	if(!list || !Array.isArray(list) || list.length<=0) return Promise.resolve(0);
	let np = new abi.Ab_NudityPromise_bA<0>();
	list.forEach((el, i)=> abi.Ab_cc_bA.Ab_IdleCallback_bA(call, [el, i, list], ()=>(i==list.length-1) ? np.Ab_resolve_bA(0) : void 0) );
	return np.Ab_promise_bA;
}

abi.Ab_cc_bA.Ab_loadBundle_bA = function(bundle_name){
	return new Promise<AssetManager.Bundle>((s, j)=>{
		assetManager.loadBundle(bundle_name, null, (err, bundle)=>{
			if(err) s(undefined);
			else if(bundle) s(bundle);
			else s(undefined);
		});
	});
};

abi.Ab_cc_bA.Ab_loadRes_bA = function(path, type, bundle, call){
	//@ts-ignore
	[bundle, call] = abi.Ab_pickValueByType_bA([bundle, call], [['object', resources], ['function', undefined]]);

	let asset = bundle.get(path, type);
	if(!asset){
		bundle.load(path, type, (err, a)=>{
			if(a) call && call(a);
			else warn('资源加载失败：', path, type, err);
		});
	}else if(call) call(asset);
}

abi.Ab_cc_bA.Ab_loadResAsync_bA = function(path, type, bundle){
	bundle = bundle??resources;

	return new Promise((s, j)=>{
		let asset = bundle.get(path, type);
		if(asset) s(asset);
		else{
			bundle.load(path, type, (err, a)=>{
				if(a) s(a);
				else warn('资源加载失败：', path, type, err);
			});

		}
	});
}

abi.Ab_cc_bA.Ab_creatEventHandle_bA = function(options){
	return Object.assign(new Component.EventHandler(), options);
}

abi.Ab_cc_bA.Ab_VecAssist_bA = class{
	private Ab_inner_bA: UITransform;
	private Ab_container_bA: UITransform;
	private Ab___vec___bA: Vec3;

	constructor(node: Node, ref: Node){
		if (!node.parent){
			abi.Ab_log_bA.Ab_tag_bA(`node<${node.name}> 不在场景中，无法使用坐标辅助类的功能!: red`);
			return void 0;
		}

		ref = ref&&ref.isValid ? ref : node.parent;

		[this.Ab_inner_bA, this.Ab_container_bA] = [node, ref].map(n=>n.getComponent(UITransform));
		this.Ab___vec___bA = v3();
	}

	private get Ab_container_upper_bA(){
		return this.Ab_container_bA.height * (1 - this.Ab_container_bA.anchorY);
	}

	private get Ab_container_bottom_bA(){
		return this.Ab_container_bA.height * this.Ab_container_bA.anchorY;
	}

	private get Ab_container_left_bA(){
		return this.Ab_container_bA.width * this.Ab_container_bA.anchorX;
	}

	private get Ab_container_right_bA(){
		return this.Ab_container_bA.width * (1 - this.Ab_container_bA.anchorX);
	}

	private get Ab_inner_upper_bA(){
		return this.Ab_inner_bA.height * (1 - this.Ab_inner_bA.anchorY);
	}

	private get Ab_inner_bottom_bA(){
		return this.Ab_inner_bA.height * this.Ab_inner_bA.anchorY;
	}

	private get Ab_inner_left_bA(){
		return this.Ab_inner_bA.width * this.Ab_inner_bA.anchorX;
	}

	private get Ab_inner_right_bA(){
		return this.Ab_inner_bA.width * (1 - this.Ab_inner_bA.anchorX);
	}

	public get Ab_top_bA(){
		return this.Ab_container_upper_bA - this.Ab_inner_upper_bA;
	}

	public get Ab_bottom_bA(){
		return this.Ab_inner_bottom_bA - this.Ab_container_bottom_bA;
	}

	public get Ab_left_bA(){
		return this.Ab_inner_left_bA - this.Ab_container_left_bA;
	}

	public get Ab_right_bA(){
		return this.Ab_container_right_bA - this.Ab_inner_right_bA;
	}

	public get Ab_over_top_bA(){
		return this.Ab_container_upper_bA + this.Ab_inner_bottom_bA;
	}

	public get Ab_over_bottom_bA(){
		return -this.Ab_container_bottom_bA - this.Ab_inner_upper_bA;
	}

	public get Ab_over_left_bA(){
		return -this.Ab_container_left_bA - this.Ab_inner_right_bA;
	}

	public get Ab_over_right_bA(){
		return this.Ab_container_right_bA + this.Ab_inner_left_bA;
	}

	public get Ab_center_bA(){
		let x = (0.5 - this.Ab_container_bA.anchorX) * this.Ab_container_bA.width + (this.Ab_inner_bA.anchorX - 0.5) * this.Ab_inner_bA.width;
		let y = (0.5 - this.Ab_container_bA.anchorY) * this.Ab_container_bA.height + (this.Ab_inner_bA.anchorY - 0.5) * this.Ab_inner_bA.height;

		return v3(x, y, this.Ab_inner_bA.node.position.z);
	}

	public get Ab_vec_bA(){
		return this.Ab___vec___bA;
	}

	public Ab_getPosition_bA(x: 'Ab_center_bA'|`Ab_${''|'over_'}${'left'|'right'|'bottom'|'top'}_bA`, y?:'Ab_center_bA'|`Ab_${''|'over_'}${'top'|'bottom'}_bA`){
		if(x.includes('top') || x.includes('bottom')){
			let _t = y;
			y = <typeof y>x;
			x = _t;
			_t = undefined;
		}

		this.Ab_vec_bA.set(
			x ? x=='Ab_center_bA' ? this.Ab_center_bA.x : Reflect.get(this, x) : this.Ab_inner_bA.node.position.x,
			y ? y=='Ab_center_bA' ? this.Ab_center_bA.y : Reflect.get(this, y) : this.Ab_inner_bA.node.position.y,
			this.Ab_inner_bA.node.position.z
		);

		return this.Ab_vec_bA;
	}

	public static Ab_getPosition_bA<Dx extends 'Ab_center_bA'|`Ab_${''|'over_'}${'left'|'right'|'bottom'|'top'}_bA`, Dy extends 'Ab_center_bA'|`Ab_${''|'over_'}${'top'|'bottom'}_bA`>(node: Node, ref?: Node|Dx, x?: Dx|Dy, y?: Dy){
		if(typeof ref == 'string'){
			[x, y as typeof x] = [ref, x];
			ref = undefined;
		}
		let va = new abi.Ab_cc_bA.Ab_VecAssist_bA(node, ref as Node);
		let vec = va.Ab_getPosition_bA(x??'Ab_center_bA', y);
		va = null;
		return vec;
	}
}

abi.Ab_cc_bA.Ab_skinPeeler_bA = function(node, sframe, inner){
	let uitrans = node.getComponent(UITransform);
	let node_size = uitrans.contentSize.clone();
	let sfrm_size = sframe.originalSize.clone();

	let sprite = node.getComponent(Sprite);
	if(!sprite) sprite = node.addComponent(Sprite);
	sprite.spriteFrame = sframe;

	let ratio: number;
	inner = inner ?? true;
	if(typeof inner=='boolean' || inner.width===inner.height){
		if(typeof inner!='boolean') inner = inner.width;
		ratio = Math[inner ? 'min' : 'max'](node_size.width / sfrm_size.width, node_size.height / sfrm_size.height);
	}else{
		let side = inner.width ? 'width' : 'height';
		ratio = node_size[side] / sfrm_size[side];
	}

	uitrans.setContentSize(sfrm_size.width * ratio, sfrm_size.height * ratio);
}

abi.Ab_cc_bA.Ab_getWorldPosition_bA = function(node, out){
	if(!node || !node.isValid) return void 0;

	return node.getWorldPosition(out??v3());
}

abi.Ab_cc_bA.Ab_getLocalPosition_bA = function(local: Node, node: Vec3|Node, out?: Vec3){
	if([local && local.isValid, node instanceof Vec3 ? true : (node && node.isValid)].includes(false)) return void 0;

	return local.getComponent(UITransform).convertToNodeSpaceAR(node instanceof Vec3 ? node : abi.Ab_cc_bA.Ab_getWorldPosition_bA(node), out??v3());
};

abi.Ab_cc_bA.Ab_v2_bA = function(__x__, y){
	if(__x__ instanceof Vec2) return __x__;

	let x: number;
	if(typeof __x__ == 'number'){
		x = __x__;
		y = y??x;
	}else ({x, y} = __x__);

	return v2(x, y);
}

abi.Ab_cc_bA.Ab_v3_bA = function(__x__, y, z){
	if(__x__ instanceof Vec3) return __x__;

	let x: number;
	if(typeof __x__ == 'number'){
		x = __x__;
		y = y??x;
		z = z??y;
	}else if(__x__ instanceof Vec2){
		z = y??0;
		({x, y} = __x__);
	}else if(__x__ instanceof Vec4){
		({x, y, z} = __x__);
	}

	return v3(x, y, z);
}

abi.Ab_cc_bA.Ab_v4_bA = function(__x__, y, z, w){
	if(__x__ instanceof Vec4) return __x__;

	let x: number;
	if(typeof __x__  == 'number'){
		x = __x__;
		y = y??x;
		z = z??y;
		w = w??z;
	}else if(__x__ instanceof Vec2){
		w = z??0;
		z = y??0;
		({x, y} = __x__);
	}else if(__x__ instanceof Vec3){
		w = z??0;
		({x, y, z} = __x__);
	}

	return v4(x, y, z, w);
}

abi.Ab_cc_bA.Ab_adaptBackgroundNode_bA = function(node, container){
	container = container ?? node.parent;
	if(!container || ![node, container].every(n=>n.isValid)) return void 0;

	let [ui_container, ui_node] = [container, node].map(n=>{
		let ui = n.getComponent(UITransform);
		if(!ui) ui = n.addComponent(UITransform);
		return ui;
	});

	let node_size: Size;
	if(node.getComponent(Sprite)) node_size = node.getComponent(Sprite).spriteFrame.originalSize;
	else node_size = ui_node.contentSize;

	let [R, r] = [ui_container, node_size].map($=>$.width / $.height);

	let ratio: number;
	if(R > r) ratio = ui_container.width / node_size.width;
	else ratio = ui_container.height / node_size.height;

	ui_node.setContentSize(node_size.width * ratio, node_size.height * ratio);
}

abi.Ab_cc_bA.Ab_updateWidget_bA = function(node, options){
	let wgt = node.getComponent(Widget);
	let remove_component = wgt ? false : true;

	if(options && remove_component){
		wgt = node.addComponent(Widget);
		Reflect.ownKeys(options)
		.forEach(key=>Reflect.set(wgt, key, Reflect.get(options, key)));
	}

	if(wgt){
		wgt.updateAlignment();
		if(remove_component){
			Promise.resolve(wgt).then(w=>{
				w.enabled = false;
				w.destroy();
			});
		}
	}

	wgt = null;
};

Reflect.defineProperty(abi.Ab_cc_bA, 'Ab_canvas_bA', {
	get(){
		return director.getScene().getComponentInChildren(Canvas);
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_size_bA, 'Ab_designSize_bA', {
	get() {
		return view.getDesignResolutionSize();
	},
	enumerable: true,
	configurable: false,
});

Reflect.defineProperty(abi.Ab_size_bA, 'Ab_canvasSize_bA', {
	get() {
		return abi.Ab_cc_bA.Ab_canvas_bA.getComponent(UITransform).contentSize;
	},
	enumerable: true,
	configurable: false,
});

abi.Ab_size_bA.Ab_innerRatio_bA = function(target, container){
	let [R, r] = [container, target].map(s=>s.width / s.height);
	/** @type {number} */
	let ratio: number;
	if(r > R) ratio = container.width / target.width;
	else ratio = container.height / target.height;
	return ratio;
}

abi.Ab_size_bA.Ab_exterRatio_bA = function(target, filler){
	let [R, r] = [target, filler].map(s=>s.width / s.height);
	/** @type {number} */
	let ratio: number;
	if(R > r) ratio = filler.height / target.height;
	else ratio = filler.width / target.width;
	return ratio;
}

abi.Ab_vector_bA.Ab_distance_bA = function(a, b){

	if([a, b].map(v=>v instanceof Vec2).includes(true)) return Vec2.subtract(v2(), abi.Ab_cc_bA.Ab_v2_bA(a), abi.Ab_cc_bA.Ab_v2_bA(b)).length();

	if([a, b].map(v=>v instanceof Vec3).includes(true)) return Vec3.subtract(v3(), abi.Ab_cc_bA.Ab_v3_bA(a), abi.Ab_cc_bA.Ab_v3_bA(b)).length();

	return Vec4.subtract(v4(), abi.Ab_cc_bA.Ab_v4_bA(a), abi.Ab_cc_bA.Ab_v4_bA(b)).length();
}